Simon Elsässer, Karolinska Institutet (2023)

DESeq2 analysis of peak universe (joint peak set called in any condition, must be called in all three replicates, MACS3)

bw_dir <- "/Volumes/DATA/DATA/Puck/bigwig/"
chromhmm <- "../genome/ESC_10_segments.mm39.bed"

library("wigglescout")
library("ggpubr")
library("ggplot2")
library("DESeq2")
library("dplyr")

Attaching package: ‘dplyr’

The following object is masked from ‘package:Biobase’:

    combine

The following object is masked from ‘package:matrixStats’:

    count

The following objects are masked from ‘package:GenomicRanges’:

    intersect, setdiff, union

The following object is masked from ‘package:GenomeInfoDb’:

    intersect

The following objects are masked from ‘package:IRanges’:

    collapse, desc, intersect, setdiff, slice, union

The following objects are masked from ‘package:S4Vectors’:

    first, intersect, rename, setdiff, setequal, union

The following objects are masked from ‘package:BiocGenerics’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library("ggrastr")
library("reshape2")

clean <- function (fn) {
  fn <- gsub(pattern = ".+/", "", x = fn)
  fn <- gsub(pattern = ".mm9.+", "", x = fn)
  fn <- gsub(pattern = ".mm39.+", "", x = fn)
  fn <- gsub(pattern = "_S.+", "", x = fn)
  fn <- gsub(pattern = ".scaled.bw", "", x = fn)
  fn <- gsub(pattern = ".unscaled.bw", "", x = fn)
  fn <- gsub(pattern = "_batch2", "", x = fn)
  fn <- gsub(pattern = "-", " ", x = fn)
  fn <- gsub(pattern = "_", " ", x = fn)
  fn <- gsub(pattern = " HA ", " ", x = fn)
  fn <- gsub(pattern = "D1D6", "FANCJ-/-", x = fn)
  fn <- gsub(pattern = "P2D2", "DHX36-/-", x = fn)
  fn <- gsub(pattern = "P3D4", "FANCJ-/-DHX36-/-", x = fn)
  return(fn)
}

BWs <- paste0(bw_dir,list.files(bw_dir,pattern="G4_.+R.\\.bw"))

mypal <-c("cornflowerblue","orange","red2","#505050")
mypal3 <-c("cornflowerblue","cornflowerblue","cornflowerblue","orange","orange","orange","red2","red2","red2","505050","505050","505050")
bw_granges_diff_analysis <- function(granges_c1,
                                     granges_c2,
                                     label_c1,
                                     label_c2,
                                     estimate_size_factors = FALSE,
                                     as_granges = FALSE) {

  # Bind first, get numbers after
  names_values <- NULL
  fields <- names(mcols(granges_c1))

  if ("name" %in% fields) {
    names_values <- mcols(granges_c1)[["name"]]
    granges_c1 <- granges_c1[, fields[fields != "name"]]
  }

  fields <- names(mcols(granges_c2))
  if ("name" %in% fields) {
    granges_c2 <- granges_c2[, fields[fields != "name"]]
  }

  cts_df <- cbind(data.frame(granges_c1), mcols(granges_c2))

  if (! is.null(names_values)) {
    rownames(cts_df) <- names_values
  }

  # Needs to drop non-complete cases and match rows
  complete <- complete.cases(cts_df)
  cts_df <- cts_df[complete, ]

  values_df <- cts_df[, 6:ncol(cts_df)] %>% dplyr::select(where(is.numeric))
  cts <- get_nreads_columns(values_df)

  condition_labels <- c(rep(label_c1, length(mcols(granges_c1))),
                        rep(label_c2, length(mcols(granges_c2))))


  coldata <- data.frame(colnames(cts), condition = as.factor(condition_labels))

  dds <- DESeq2::DESeqDataSetFromMatrix(countData = cts,
                                colData = coldata,
                                design = ~ condition,
                                rowRanges = granges_c1[complete, ])


  if (estimate_size_factors == TRUE) {
    dds <- DESeq2::estimateSizeFactors(dds)
  }
  else {
    # Since files are scaled, we do not want to estimate size factors
    sizeFactors(dds) <- c(rep(1, ncol(cts)))
  }

  dds <- DESeq2::estimateDispersions(dds)
  dds <- DESeq2::nbinomWaldTest(dds)

  if (as_granges) {
    result <- DESeq2::results(dds, format = "GRanges",alpha = 0.01)
    if (!is.null(names_values)) {
      result$name <- names_values[complete]
    }

  }
  else {
    # result <- results(dds, format="DataFrame")
    result <- dds
  }

  result
}

get_nreads_columns <- function(df, length_factor = 100) {
  # Convert mean coverages to round integer read numbers
  cts <- as.matrix(df)
  cts <- as.matrix(cts[complete.cases(cts),])
  cts <- round(cts*length_factor)
  cts
}

peak_universe <- "../peaks/G4_combined_min3rep.bed"

BWs.WT <- BWs[grep("WT",BWs)]
BWs.FANCJ <- BWs[grep("D1D6",BWs)]
BWs.DHX36 <- BWs[grep("P2D2",BWs)]
BWs.DKO <- BWs[grep("P3D4",BWs)]
  
# Calculate here some loci or bins
cov.WT <- bw_loci(BWs.WT, loci = peak_universe)

Attaching package: ‘purrr’

The following object is masked from ‘package:GenomicRanges’:

    reduce

The following object is masked from ‘package:IRanges’:

    reduce
cov.DHX36 <- bw_loci(BWs.DHX36, loci = peak_universe)
cov.FANCJ <- bw_loci(BWs.FANCJ, loci = peak_universe)
cov.DKO <- bw_loci(BWs.DKO, loci = peak_universe)

cov.WT$name <- paste0("peak_",1:length(cov.WT))
cov.DHX36$name <- paste0("peak_",1:length(cov.DHX36))
cov.FANCJ$name <- paste0("peak_",1:length(cov.FANCJ))
cov.DKO$name <- paste0("peak_",1:length(cov.DKO))
diff_DHX36 <- bw_granges_diff_analysis(cov.WT, cov.DHX36,
                                     "WT", "DHX36KO")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
diff_FANCJ <- bw_granges_diff_analysis(cov.WT, cov.FANCJ,
                                     "WT", "FANCJ")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
diff_DKO <- bw_granges_diff_analysis(cov.WT, cov.DKO,
                                     "WT", "DKO")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
# This takes care of low conts and things like this, but you can also use
# diff_results as is for the things below
lfc_DHX36 <- DESeq2::lfcShrink(diff_DHX36, coef = "condition_WT_vs_DHX36KO", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
lfc_FANCJ <- DESeq2::lfcShrink(diff_FANCJ, coef = "condition_WT_vs_FANCJ", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
lfc_DKO <- DESeq2::lfcShrink(diff_DKO, coef = "condition_WT_vs_DKO", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
data_DHX36 <- plotMA(lfc_DHX36, returnData = T)
data_DHX36$lfc <- -data_DHX36$lfc
data_DHX36$mean <- log10(data_DHX36$mean)

data_FANCJ <- plotMA(lfc_FANCJ, returnData = T)
data_FANCJ$lfc <- -data_FANCJ$lfc
data_FANCJ$mean <- log10(data_FANCJ$mean)

data_DKO <- plotMA(lfc_DKO, returnData = T)
data_DKO$lfc <- -data_DKO$lfc
data_DKO$mean <- log10(data_DKO$mean)
ggscatter(data_DHX36,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

plot_MA_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600) 
data_DHX36$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DHX36$cov.DHX36 <- rowMeans(as.data.frame(cov.DHX36)[,6:8])
ggscatter(data_DHX36,x ="cov.WT",y="cov.DHX36",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600) 
data_DHX36$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DHX36$cov.DHX36 <- rowMeans(as.data.frame(cov.DHX36)[,6:8])
ggscatter(data_DHX36,x ="cov.WT",y="cov.DHX36",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + scale_x_continuous(limits = c(-10,50)) + scale_y_continuous(limits = c(-10,50)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DHX36_zoom <- rasterize(last_plot(), layers='Point', dpi=600) 
ggscatter(data_FANCJ,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[2])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600) 
data_FANCJ$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_FANCJ$cov.FANCJ <- rowMeans(as.data.frame(cov.FANCJ)[,6:8])
ggscatter(data_FANCJ,x ="cov.WT",y="cov.FANCJ",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[2])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600) 
ggscatter(data_DKO,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_DKO <- rasterize(last_plot(), layers='Point', dpi=600) 
data_DKO$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DKO$cov.DKO <- rowMeans(as.data.frame(cov.DKO)[,6:8])
ggscatter(data_DKO,x ="cov.WT",y="cov.DKO",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DKO <- rasterize(last_plot(), layers='Point', dpi=600) 
data_DKO$lfc_DHX36 <- data_DHX36$lfc
data_DKO$lfc_FANCJ <- data_FANCJ$lfc
ggscatter(data_DKO,x ="lfc_DHX36",y="lfc",color="gray",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]), add = "reg.line")+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5)) + stat_cor()

plot_LFC_DKO_vs_DHX36_reg <- rasterize(last_plot(), layers='Point', dpi=600) 

ggscatter(data_DKO,x ="lfc_FANCJ",y="lfc",color="gray",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]), add="reg.line")+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5)) + stat_cor()

plot_LFC_DKO_vs_FANCJ_reg <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_DKO,x ="lfc_FANCJ",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5)) + stat_cor()

plot_LFC_DKO_vs_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$lfc_DKO <- data_DKO$lfc
ggscatter(data_DHX36,x ="lfc",y="lfc_DKO",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

bed <- as.data.frame(cov.DHX36)[,1:3]

results_table <- data.frame(chr=bed$seqnames,start=bed$start,end=bed$end,name=cov.WT$name, baseMean=lfc_DKO$baseMean,DHX36=data_DHX36$isDE,FANCJ=data_FANCJ$isDE,DKO=data_DKO$isDE,DHX36lfc=data_DHX36$lfc,FANCJlfc=data_FANCJ$lfc,DKOlfc=data_DKO$lfc,dir=".")

results_table$nonsig <- !(results_table$DHX36 | results_table$FANCJ | results_table$DKO)

results_table$sig <- factor("lowlfc", levels=c("nonsig","lowlfc","FANCJ","DHX36","DKO"))
results_table$sig[(results_table$nonsig)] <- "nonsig"
results_table$sig[(results_table$DKO & results_table$DKOlfc>1)] <- "DKO"
results_table$sig[(results_table$DHX36 & results_table$DHX36lfc>1)] <- "DHX36"
results_table$sig[(results_table$FANCJ & results_table$FANCJlfc>1)] <- "FANCJ"

write.table(results_table,"G4_CnT_combined_peaks_DESeq_results.txt", row.names = F, col.names = T,quote = F, sep = "\t")
results_table <- read.table("G4_CnT_combined_peaks_DESeq_results.txt", header = T, sep = "\t")
results_table$sig <- factor(results_table$sig, levels=c("nonsig","lowlfc","FANCJ","DHX36","DKO"))

DHX36_bed <- results_table[(results_table$DHX36 & results_table$DHX36lfc>1),c(1,2,3,4,9,12)]
write.table(DHX36_bed,"../peaks/G4_CnT_combined_peaks_DESeq_DHX36_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")

FANCJ_bed <- results_table[(results_table$FANCJ & results_table$FANCJlfc>1),c(1,2,3,4,10,12)]
write.table(FANCJ_bed,"../peaks/G4_CnT_combined_peaks_DESeq_FANCJ_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")

DKO_bed <- results_table[(results_table$DKO & results_table$DKOlfc>1),c(1,2,3,4,11,12)]
write.table(DKO_bed,"../peaks/G4_CnT_combined_peaks_DESeq_DKO_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")

nonsig_bed <- results_table[results_table$nonsig ,c(1,2,3,4,11,12)]
write.table(nonsig_bed,"../peaks/G4_CnT_combined_peaks_DESeq_nonsig.bed", row.names = F, col.names = F,quote = F, sep = "\t")

DKO_bed_top <- results_table[(results_table$DKO==TRUE & results_table$DKOlfc>2 & results_table$baseMean > 100),c(1,2,3,4,11,12)]
write.table(DKO_bed_top,"../peaks/G4_CnT_combined_peaks_DESeq_DKO_sig_lfc_base_cutoff.bed", row.names = F, col.names = F,quote = F, sep = "\t")


write.table(cbind(results_table[,c(1,2,3)],results_table$sig,as.numeric(results_table$sig),"."),"../peaks/G4_CnT_combined_peaks_DESeq_sig_categories.bed", row.names = F, col.names = F,quote = F, sep = "\t")
library(eulerr)
v <- list(DHX36=DHX36_bed$name,FANCJ=FANCJ_bed$name,DKO=DKO_bed$name)
plot_Venn_all <- plot(euler(v),quantities=T, border="black")
plot_Venn_all

library(eulerr)
DKOneg <- results_table[(results_table$DKO==TRUE & results_table$DKOlfc< -1),c(4)]
v <- list(all=cov.WT$name,DKOneg=DKOneg,DKO=DKO_bed$name)
plot_Venn_DKO <- plot(euler(v),quantities=T)
plot_Venn_DKO

dir.create("./plots",showWarnings = F)
ggsave("plots/peaks_DESeq2_MA_DHX36.pdf",plot_MA_DHX36,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_MA_FANCJ.pdf",plot_MA_FANCJ,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_MA_DKO.pdf",plot_MA_DKO,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_LFC_DHX36.pdf",plot_LFC_DKO_vs_DHX36,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_LFC_FANCJ.pdf",plot_LFC_DKO_vs_FANCJ,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_Venn_KOs.pdf",plot_Venn_all,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_Venn_DKO_vs_all.pdf",plot_Venn_DKO,width = 4, height= 4)
library(cowplot)

Attaching package: ‘cowplot’

The following object is masked from ‘package:ggpubr’:

    get_legend
dir.create("./panels",showWarnings = F)

library("cowplot")
p <- ggdraw() +
  draw_plot(plot_MA_DHX36, x = 0, y = 0.5, width = .33, height = .5) +
  draw_plot(plot_MA_FANCJ, x = .33, y = 0.5, width = .33, height = .5) +
  draw_plot(plot_MA_DKO, x = 0.66, y = 0.5, width = .33, height = 0.5) +
  draw_plot(plot_LFC_DKO_vs_DHX36, x = 0, y = 0, width = 0.33, height = 0.5) +
  draw_plot(plot_LFC_DKO_vs_FANCJ, x = 0.33, y = 0, width = 0.33, height = 0.5) +
  draw_plot(plot_Venn_all, x = 0.66, y = 0, width = 0.33, height = 0.5) +
  draw_plot_label(label = c("a", "b", "c","d","e","f"), size = 15,
                  x = c(0, 0.33, 0.66, 0, 0.33, 0.66), y = c(1, 1, 1, 0.5, 0.5, 0.5))
p

ggsave("panels/peaks_DESeq2.pdf",p)
Saving 12 x 8 in image

cov <- cbind( as.data.frame(cov.WT)[,1:8], 
              as.data.frame(cov.DHX36)[,6:8], 
              as.data.frame(cov.FANCJ)[,6:8], 
              as.data.frame(cov.DKO)[,6:8])

colnames(cov) <- c(colnames(cov)[1:5],"WT1","WT2","WT3","DHX1","DHX2","DHX3","FAN1","FAN2","FAN3","DKO1","DKO2","DKO3")

rownames(cov) <- as.data.frame(cov.WT)$name

cov$DHX36_sig <- rownames(cov) %in% DHX36_bed$name
cov$FANCJ_sig <- rownames(cov) %in% FANCJ_bed$name
cov$DKO_sig <- rownames(cov) %in% DKO_bed$name
cov$non_sig <- with(cov, !(DHX36_sig | FANCJ_sig | DKO_sig))
library(reshape2)
mdf <- melt(data.frame(name=rownames(cov),cov[,6:21]))
Using name, DHX36_sig, FANCJ_sig, DKO_sig, non_sig as id variables
mdf <- mdf[mdf$value<500,]
mdf$cond <- "WT"
mdf$cond[grep("DHX",mdf$variable)] <- "DHX36-/-"
mdf$cond[grep("FAN",mdf$variable)] <- "FANCJ-/-"
mdf$cond[grep("DKO",mdf$variable)] <- "DHX36-/-FANCJ-/-"
plot_viol_rep_all_peaks <- ggviolin(mdf, x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
  coord_cartesian(ylim=c(0,50))
plot_viol_rep_all_peaks

plot_viol_rep_DHX36_peaks <- ggviolin(mdf[mdf$DHX36_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
  coord_cartesian(ylim=c(0,50))
plot_viol_rep_DHX36_peaks

ggviolin(mdf[mdf$FANCJ_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
  coord_cartesian(ylim=c(0,50))

plot_viol_rep_DKO_peaks <- ggviolin(mdf[mdf$DKO_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
  coord_cartesian(ylim=c(0,50))
plot_viol_rep_DKO_peaks

plot_viol_rep_nonsig_peaks <- ggviolin(mdf[mdf$non_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
  coord_cartesian(ylim=c(0,50))
plot_viol_rep_nonsig_peaks

ggsave("plots/peaks_DESeq2_viol_rep_all.pdf",plot_viol_rep_all_peaks)
Saving 7 x 7 in image
ggsave("plots/peaks_DESeq2_viol_rep_DKO.pdf",plot_viol_rep_DKO_peaks)
ggsave("plots/peaks_DESeq2_viol_rep_DHX36.pdf",plot_viol_rep_DHX36_peaks)
ggsave("plots/peaks_DESeq2_viol_rep_nonsig.pdf",plot_viol_rep_nonsig_peaks)
sdf <- aggregate(value ~ name + cond, data=mdf, FUN="mean")
sdf$cond <- factor(sdf$cond,levels=c("WT","DHX36-/-","FANCJ-/-","DHX36-/-FANCJ-/-"))
ggviolin(sdf, x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
  coord_cartesian(ylim=c(0,50))

sdf$DHX36_sig <- sdf$name %in% DHX36_bed$name
sdf$FANCJ_sig <- sdf$name %in% FANCJ_bed$name
sdf$DKO_sig <- sdf$name %in% DKO_bed$name
sdf$DKO_top <- sdf$name %in% DKO_bed_top$name
ggviolin(sdf[sdf$DHX36,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
  coord_cartesian(ylim=c(0,75))

ggviolin(sdf[sdf$FANCJ_sig,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
  coord_cartesian(ylim=c(0,75))

plot_viol_DKO_peaks <- ggviolin(sdf[sdf$DKO_sig,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
  coord_cartesian(ylim=c(0,75))
plot_viol_DKO_peaks

ggviolin(sdf[sdf$DKO_top,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
  coord_cartesian(ylim=c(0,75))

annotate peak table

library(bedscout)

peak_universe <- "../peaks/G4_combined_min3rep.bed"

bed_peaks <- rtracklayer::import(peak_universe)
chromhmm_gr <- rtracklayer::import(chromhmm)


bed_peaks_annotated <- unique(impute_feature(bed_peaks, chromhmm_gr, "name"))
bed_peaks_annotated_df <- as.data.frame(bed_peaks_annotated)
# If you want to export to BED file with rtracklayer then you
# do need to explicitly overwrite the name:
bed_peaks_annotated$name <- bed_peaks_annotated$feature
rtracklayer::export(unique(bed_peaks_annotated), "../peaks/G4_CnT_combined_peaks_DESeq_annotated_v2.bed")

chromhmm17_gr <- rtracklayer::import("../genome/ChromHMM17.chr9.mm39lift.bed")
bed_peaks_hmm17 <- unique(impute_feature(bed_peaks, chromhmm17_gr, "name"))
# If you want to export to BED file with rtracklayer then you
# do need to explicitly overwrite the name:
bed_peaks_hmm17$name <- bed_peaks_hmm17$feature
bed_peaks_hmm17$score[is.na(bed_peaks_hmm17$score)] <- 0
rtracklayer::export(bed_peaks_hmm17, "../peaks/G4_CnT_combined_peaks_DESeq_annotated_ChromHMM17.bed")

rmsk_gr <- rtracklayer::import("../genome/rmsk.lt200bp.mm39.bed")
bed_peaks_rmsk <- impute_feature(bed_peaks, rmsk_gr, "name")
# If you want to export to BED file with rtracklayer then you
# do need to explicitly overwrite the name:
bed_peaks_rmsk$name <- bed_peaks_rmsk$feature
Error: object 'bed_peaks_rmsk' not found
#read in - if you want to skip de novo generation
bed_peaks_table <- read.table("G4_CnT_combined_peaks_DESeq_annotated_v2.txt", header = T, sep = "\t")

vpal=colorRampPalette(c("cornflowerblue","orange","red2"))
stats <- as.data.frame(table(bed_peaks_table$feature))
plot_donut_all <- ggdonutchart(stats,x = "Freq",label="Var1",fill=vpal(10))
plot_donut_all

DJ Peak Annotation

bed_DJ <- bed_peaks_table[bed_peaks_table$DKO,c(1,2,3,6,16,5)]
bed_DJ$name <- "DJ"
write.table(bed_DJ,"../peaks/G4_CnT_combined_peaks_DJ.bed", row.names = F, col.names = F,quote = F, sep = "\t")

stats <- as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO]))
plot_donut_DJ <- ggdonutchart(stats,x = "Freq",label="Var1",fill=vpal(10))
plot_donut_DJ

non-DJ Peak Annotation

bed_nonDJ <- bed_peaks_table[bed_peaks_table$nonsig,c(1,2,3,6,16,5)]
bed_nonDJ$name <- "nonDJ"
write.table(bed_nonDJ,"../peaks/G4_CnT_combined_peaks_nonDJ.bed", row.names = F, col.names = F,quote = F, sep = "\t")

bed_DJ$DKOlfc <- 1
bed_nonDJ$DKOlfc <- 0

write.table(rbind(bed_DJ,bed_nonDJ),"../peaks/G4_CnT_combined_peaks_DJ_nonDJ.bed", row.names = F, col.names = F,quote = F, sep = "\t")

stats <- as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$nonsig]))
plot_donut_nonDJ <- ggdonutchart(stats,x = "Freq",label="Var1",fill=vpal(10))
plot_donut_nonDJ

ggsave("plots/plot_donut_DJ.pdf",plot_donut_DJ)
Saving 7 x 7 in image
ggsave("plots/plot_donut_nonDJ.pdf",plot_donut_nonDJ)
ggsave("plots/plot_donut_all.pdf",plot_donut_all)
vpal=colorRampPalette(c("lightgreen","cornflowerblue","orange","red2"))

stats <- data.frame(as.data.frame(table(bed_peaks_table$feature))[1],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO]))[2],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$nonsig]))[2])

colnames(stats) <- c("State","DJ","nonDJ")

#stats$DHX36=stats$DJ/sum(stats$DJ)*100
#stats$FANCJ=stats$nonDJ/sum(stats$nonDJ)*100

mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols,  orientation = c("horizontal")) 
plot_bar_chromhmm_anno

vpal=colorRampPalette(c("lightgreen","cornflowerblue","orange","red2"))

stats <- data.frame(as.data.frame(table(bed_peaks_table$feature))[1],as.data.frame(table(bed_peaks_table$feature))[2],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO]))[2],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$nonsig]))[2])

colnames(stats) <- c("State","all","DJ","nonDJ")

#stats$DHX36=stats$DJ/sum(stats$DJ)*100
#stats$FANCJ=stats$nonDJ/sum(stats$nonDJ)*100

mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno_all <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols,  orientation = c("horizontal")) 
plot_bar_chromhmm_anno_all

stats$DJ=stats$DJ/sum(stats$DJ)*100
stats$nonDJ=stats$nonDJ/sum(stats$nonDJ)*100
stats$all=stats$all/sum(stats$all)*100
mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno_norm <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols,  orientation = c("horizontal")) 
plot_bar_chromhmm_anno_norm

ggsave("plots/plot_bar_chromhmm.pdf",plot_bar_chromhmm_anno)
Saving 7 x 7 in image
ggsave("plots/plot_bar_chromhmm_rel.pdf",plot_bar_chromhmm_anno_norm)
vpal=colorRampPalette(c("lightgreen","cornflowerblue","orange","red2"))

stats <- data.frame(as.data.frame(table(bed_peaks_table$feature)),DHX36=as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DHX36==TRUE]))[2],FANCJ=as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$FANCJ==TRUE]))[2],DKO=as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO==TRUE]))[2])
colnames(stats) <- c("State","Total","DHX36","FANCJ","DKO")

stats$Total=stats$Total/sum(stats$Total)*100
stats$DHX36=stats$DHX36/sum(stats$DHX36)*100
stats$FANCJ=stats$FANCJ/sum(stats$FANCJ)*100
stats$DKO=stats$DKO/sum(stats$DKO)*100
mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols,label=mdf$State)
plot_bar_chromhmm_anno

p <- ggdraw() +
  draw_plot(plot_bar_chromhmm_anno, x = 0, y = 0, width = .20, height = 1) +
  draw_plot(plot_viol_rep_DKO_peaks, x = .2, y = 0, width = .40, height = 0.7) +
  draw_plot(plot_viol_rep_nonsig_peaks, x = 0.6, y = 0, width = .40, height = 0.7) +
  draw_plot_label(label = c("a", "b", "c"), size = 15,
                  x = c(0, 0.2, 0.6), y = c(1, 0.8, 0.8))
p

ggsave("panels/peak_anno_violin_v1.pdf",p)
Saving 16 x 6 in image

p <- ggdraw() +
  draw_plot(plot_bar_chromhmm_anno, x = 0, y = 0, width = .4, height = 1) +
  draw_plot(plot_viol_rep_DKO_peaks, x = .4, y = 0.5, width = .60, height = 0.5) +
  draw_plot(plot_viol_rep_nonsig_peaks, x = 0.4, y = 0, width = .60, height = 0.5) +
  draw_plot_label(label = c("a", "b", "c"), size = 15,
                  x = c(0, 0.4, 0.4), y = c(1, 1, 0.5))
p

ggsave("panels/peak_anno_violin_v2.pdf",p)
Saving 16 x 6 in image
LS0tCnRpdGxlOiAiRzQgQ1VUJlRhZyBhbmFseXNpcyBtRVNDIChXVCwgRkFOQ0ogS08sIERIWDM2IEtPLCBES08pIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpTaW1vbiBFbHPDpHNzZXIsIEthcm9saW5za2EgSW5zdGl0dXRldCAoMjAyMykKCiMjIyBERVNlcTIgYW5hbHlzaXMgb2YgcGVhayB1bml2ZXJzZSAoam9pbnQgcGVhayBzZXQgY2FsbGVkIGluIGFueSBjb25kaXRpb24sIG11c3QgYmUgY2FsbGVkIGluIGFsbCB0aHJlZSByZXBsaWNhdGVzLCBNQUNTMykKCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQpid19kaXIgPC0gIi9Wb2x1bWVzL0RBVEEvREFUQS9QdWNrL2JpZ3dpZy8iCmNocm9taG1tIDwtICIuLi9nZW5vbWUvRVNDXzEwX3NlZ21lbnRzLm1tMzkuYmVkIgoKbGlicmFyeSgid2lnZ2xlc2NvdXQiKQpsaWJyYXJ5KCJnZ3B1YnIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJnZ3Jhc3RyIikKbGlicmFyeSgicmVzaGFwZTIiKQoKY2xlYW4gPC0gZnVuY3Rpb24gKGZuKSB7CiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi4rLyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi5tbTkuKyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi5tbTM5LisiLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJfUy4rIiwgIiIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiLnNjYWxlZC5idyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi51bnNjYWxlZC5idyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIl9iYXRjaDIiLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICItIiwgIiAiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIl8iLCAiICIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiIEhBICIsICIgIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJEMUQ2IiwgIkZBTkNKLS8tIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJQMkQyIiwgIkRIWDM2LS8tIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJQM0Q0IiwgIkZBTkNKLS8tREhYMzYtLy0iLCB4ID0gZm4pCiAgcmV0dXJuKGZuKQp9CgpCV3MgPC0gcGFzdGUwKGJ3X2RpcixsaXN0LmZpbGVzKGJ3X2RpcixwYXR0ZXJuPSJHNF8uK1IuXFwuYnciKSkKCm15cGFsIDwtYygiY29ybmZsb3dlcmJsdWUiLCJvcmFuZ2UiLCJyZWQyIiwiIzUwNTA1MCIpCm15cGFsMyA8LWMoImNvcm5mbG93ZXJibHVlIiwiY29ybmZsb3dlcmJsdWUiLCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsIm9yYW5nZSIsIm9yYW5nZSIsInJlZDIiLCJyZWQyIiwicmVkMiIsIjUwNTA1MCIsIjUwNTA1MCIsIjUwNTA1MCIpCmBgYAoKYGBge3J9CmJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyA8LSBmdW5jdGlvbihncmFuZ2VzX2MxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3Jhbmdlc19jMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2MxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfYzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZV9zaXplX2ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzX2dyYW5nZXMgPSBGQUxTRSkgewoKICAjIEJpbmQgZmlyc3QsIGdldCBudW1iZXJzIGFmdGVyCiAgbmFtZXNfdmFsdWVzIDwtIE5VTEwKICBmaWVsZHMgPC0gbmFtZXMobWNvbHMoZ3Jhbmdlc19jMSkpCgogIGlmICgibmFtZSIgJWluJSBmaWVsZHMpIHsKICAgIG5hbWVzX3ZhbHVlcyA8LSBtY29scyhncmFuZ2VzX2MxKVtbIm5hbWUiXV0KICAgIGdyYW5nZXNfYzEgPC0gZ3Jhbmdlc19jMVssIGZpZWxkc1tmaWVsZHMgIT0gIm5hbWUiXV0KICB9CgogIGZpZWxkcyA8LSBuYW1lcyhtY29scyhncmFuZ2VzX2MyKSkKICBpZiAoIm5hbWUiICVpbiUgZmllbGRzKSB7CiAgICBncmFuZ2VzX2MyIDwtIGdyYW5nZXNfYzJbLCBmaWVsZHNbZmllbGRzICE9ICJuYW1lIl1dCiAgfQoKICBjdHNfZGYgPC0gY2JpbmQoZGF0YS5mcmFtZShncmFuZ2VzX2MxKSwgbWNvbHMoZ3Jhbmdlc19jMikpCgogIGlmICghIGlzLm51bGwobmFtZXNfdmFsdWVzKSkgewogICAgcm93bmFtZXMoY3RzX2RmKSA8LSBuYW1lc192YWx1ZXMKICB9CgogICMgTmVlZHMgdG8gZHJvcCBub24tY29tcGxldGUgY2FzZXMgYW5kIG1hdGNoIHJvd3MKICBjb21wbGV0ZSA8LSBjb21wbGV0ZS5jYXNlcyhjdHNfZGYpCiAgY3RzX2RmIDwtIGN0c19kZltjb21wbGV0ZSwgXQoKICB2YWx1ZXNfZGYgPC0gY3RzX2RmWywgNjpuY29sKGN0c19kZildICU+JSBkcGx5cjo6c2VsZWN0KHdoZXJlKGlzLm51bWVyaWMpKQogIGN0cyA8LSBnZXRfbnJlYWRzX2NvbHVtbnModmFsdWVzX2RmKQoKICBjb25kaXRpb25fbGFiZWxzIDwtIGMocmVwKGxhYmVsX2MxLCBsZW5ndGgobWNvbHMoZ3Jhbmdlc19jMSkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGxhYmVsX2MyLCBsZW5ndGgobWNvbHMoZ3Jhbmdlc19jMikpKSkKCgogIGNvbGRhdGEgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyhjdHMpLCBjb25kaXRpb24gPSBhcy5mYWN0b3IoY29uZGl0aW9uX2xhYmVscykpCgogIGRkcyA8LSBERVNlcTI6OkRFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY3RzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gY29uZGl0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd1JhbmdlcyA9IGdyYW5nZXNfYzFbY29tcGxldGUsIF0pCgoKICBpZiAoZXN0aW1hdGVfc2l6ZV9mYWN0b3JzID09IFRSVUUpIHsKICAgIGRkcyA8LSBERVNlcTI6OmVzdGltYXRlU2l6ZUZhY3RvcnMoZGRzKQogIH0KICBlbHNlIHsKICAgICMgU2luY2UgZmlsZXMgYXJlIHNjYWxlZCwgd2UgZG8gbm90IHdhbnQgdG8gZXN0aW1hdGUgc2l6ZSBmYWN0b3JzCiAgICBzaXplRmFjdG9ycyhkZHMpIDwtIGMocmVwKDEsIG5jb2woY3RzKSkpCiAgfQoKICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZURpc3BlcnNpb25zKGRkcykKICBkZHMgPC0gREVTZXEyOjpuYmlub21XYWxkVGVzdChkZHMpCgogIGlmIChhc19ncmFuZ2VzKSB7CiAgICByZXN1bHQgPC0gREVTZXEyOjpyZXN1bHRzKGRkcywgZm9ybWF0ID0gIkdSYW5nZXMiLGFscGhhID0gMC4wMSkKICAgIGlmICghaXMubnVsbChuYW1lc192YWx1ZXMpKSB7CiAgICAgIHJlc3VsdCRuYW1lIDwtIG5hbWVzX3ZhbHVlc1tjb21wbGV0ZV0KICAgIH0KCiAgfQogIGVsc2UgewogICAgIyByZXN1bHQgPC0gcmVzdWx0cyhkZHMsIGZvcm1hdD0iRGF0YUZyYW1lIikKICAgIHJlc3VsdCA8LSBkZHMKICB9CgogIHJlc3VsdAp9CgpnZXRfbnJlYWRzX2NvbHVtbnMgPC0gZnVuY3Rpb24oZGYsIGxlbmd0aF9mYWN0b3IgPSAxMDApIHsKICAjIENvbnZlcnQgbWVhbiBjb3ZlcmFnZXMgdG8gcm91bmQgaW50ZWdlciByZWFkIG51bWJlcnMKICBjdHMgPC0gYXMubWF0cml4KGRmKQogIGN0cyA8LSBhcy5tYXRyaXgoY3RzW2NvbXBsZXRlLmNhc2VzKGN0cyksXSkKICBjdHMgPC0gcm91bmQoY3RzKmxlbmd0aF9mYWN0b3IpCiAgY3RzCn0KYGBgCgpgYGB7cn0KCnBlYWtfdW5pdmVyc2UgPC0gIi4uL3BlYWtzL0c0X2NvbWJpbmVkX21pbjNyZXAuYmVkIgoKQldzLldUIDwtIEJXc1tncmVwKCJXVCIsQldzKV0KQldzLkZBTkNKIDwtIEJXc1tncmVwKCJEMUQ2IixCV3MpXQpCV3MuREhYMzYgPC0gQldzW2dyZXAoIlAyRDIiLEJXcyldCkJXcy5ES08gPC0gQldzW2dyZXAoIlAzRDQiLEJXcyldCiAgCiMgQ2FsY3VsYXRlIGhlcmUgc29tZSBsb2NpIG9yIGJpbnMKY292LldUIDwtIGJ3X2xvY2koQldzLldULCBsb2NpID0gcGVha191bml2ZXJzZSkKY292LkRIWDM2IDwtIGJ3X2xvY2koQldzLkRIWDM2LCBsb2NpID0gcGVha191bml2ZXJzZSkKY292LkZBTkNKIDwtIGJ3X2xvY2koQldzLkZBTkNKLCBsb2NpID0gcGVha191bml2ZXJzZSkKY292LkRLTyA8LSBid19sb2NpKEJXcy5ES08sIGxvY2kgPSBwZWFrX3VuaXZlcnNlKQoKY292LldUJG5hbWUgPC0gcGFzdGUwKCJwZWFrXyIsMTpsZW5ndGgoY292LldUKSkKY292LkRIWDM2JG5hbWUgPC0gcGFzdGUwKCJwZWFrXyIsMTpsZW5ndGgoY292LkRIWDM2KSkKY292LkZBTkNKJG5hbWUgPC0gcGFzdGUwKCJwZWFrXyIsMTpsZW5ndGgoY292LkZBTkNKKSkKY292LkRLTyRuYW1lIDwtIHBhc3RlMCgicGVha18iLDE6bGVuZ3RoKGNvdi5ES08pKQpgYGAKCmBgYHtyfQpkaWZmX0RIWDM2IDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YuV1QsIGNvdi5ESFgzNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXVCIsICJESFgzNktPIikKZGlmZl9GQU5DSiA8LSBid19ncmFuZ2VzX2RpZmZfYW5hbHlzaXMoY292LldULCBjb3YuRkFOQ0osCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV1QiLCAiRkFOQ0oiKQpkaWZmX0RLTyA8LSBid19ncmFuZ2VzX2RpZmZfYW5hbHlzaXMoY292LldULCBjb3YuREtPLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldUIiwgIkRLTyIpCgoKIyBUaGlzIHRha2VzIGNhcmUgb2YgbG93IGNvbnRzIGFuZCB0aGluZ3MgbGlrZSB0aGlzLCBidXQgeW91IGNhbiBhbHNvIHVzZQojIGRpZmZfcmVzdWx0cyBhcyBpcyBmb3IgdGhlIHRoaW5ncyBiZWxvdwpsZmNfREhYMzYgPC0gREVTZXEyOjpsZmNTaHJpbmsoZGlmZl9ESFgzNiwgY29lZiA9ICJjb25kaXRpb25fV1RfdnNfREhYMzZLTyIsIHR5cGU9ImFwZWdsbSIpCmxmY19GQU5DSiA8LSBERVNlcTI6OmxmY1NocmluayhkaWZmX0ZBTkNKLCBjb2VmID0gImNvbmRpdGlvbl9XVF92c19GQU5DSiIsIHR5cGU9ImFwZWdsbSIpCmxmY19ES08gPC0gREVTZXEyOjpsZmNTaHJpbmsoZGlmZl9ES08sIGNvZWYgPSAiY29uZGl0aW9uX1dUX3ZzX0RLTyIsIHR5cGU9ImFwZWdsbSIpCgpkYXRhX0RIWDM2IDwtIHBsb3RNQShsZmNfREhYMzYsIHJldHVybkRhdGEgPSBUKQpkYXRhX0RIWDM2JGxmYyA8LSAtZGF0YV9ESFgzNiRsZmMKZGF0YV9ESFgzNiRtZWFuIDwtIGxvZzEwKGRhdGFfREhYMzYkbWVhbikKCmRhdGFfRkFOQ0ogPC0gcGxvdE1BKGxmY19GQU5DSiwgcmV0dXJuRGF0YSA9IFQpCmRhdGFfRkFOQ0okbGZjIDwtIC1kYXRhX0ZBTkNKJGxmYwpkYXRhX0ZBTkNKJG1lYW4gPC0gbG9nMTAoZGF0YV9GQU5DSiRtZWFuKQoKZGF0YV9ES08gPC0gcGxvdE1BKGxmY19ES08sIHJldHVybkRhdGEgPSBUKQpkYXRhX0RLTyRsZmMgPC0gLWRhdGFfREtPJGxmYwpkYXRhX0RLTyRtZWFuIDwtIGxvZzEwKGRhdGFfREtPJG1lYW4pCmBgYAoKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9Cmdnc2NhdHRlcihkYXRhX0RIWDM2LHggPSJtZWFuIix5PSJsZmMiLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFsxXSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTUsNSkpCnBsb3RfTUFfREhYMzYgPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkgCmBgYApgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpkYXRhX0RIWDM2JGNvdi5XVCA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5XVClbLDY6OF0pCmRhdGFfREhYMzYkY292LkRIWDM2IDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LkRIWDM2KVssNjo4XSkKZ2dzY2F0dGVyKGRhdGFfREhYMzYseCA9ImNvdi5XVCIseT0iY292LkRIWDM2Iixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbMV0pKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKQpwbG90X1hZX0RIWDM2IDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZGF0YV9ESFgzNiRjb3YuV1QgPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuV1QpWyw2OjhdKQpkYXRhX0RIWDM2JGNvdi5ESFgzNiA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5ESFgzNilbLDY6OF0pCmdnc2NhdHRlcihkYXRhX0RIWDM2LHggPSJjb3YuV1QiLHk9ImNvdi5ESFgzNiIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzFdKSkgKyBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTAsNTApKSArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xMCw1MCkpICsgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpCnBsb3RfWFlfREhYMzZfem9vbSA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpnZ3NjYXR0ZXIoZGF0YV9GQU5DSix4ID0ibWVhbiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbMl0pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpKQpwbG90X01BX0ZBTkNKIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfRkFOQ0okY292LldUIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LldUKVssNjo4XSkKZGF0YV9GQU5DSiRjb3YuRkFOQ0ogPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuRkFOQ0opWyw2OjhdKQpnZ3NjYXR0ZXIoZGF0YV9GQU5DSix4ID0iY292LldUIix5PSJjb3YuRkFOQ0oiLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFsyXSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKQpwbG90X1hZX0ZBTkNKIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9Cmdnc2NhdHRlcihkYXRhX0RLTyx4ID0ibWVhbiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpKQpwbG90X01BX0RLTyA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpkYXRhX0RLTyRjb3YuV1QgPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuV1QpWyw2OjhdKQpkYXRhX0RLTyRjb3YuREtPIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LkRLTylbLDY6OF0pCmdnc2NhdHRlcihkYXRhX0RLTyx4ID0iY292LldUIix5PSJjb3YuREtPIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkKcGxvdF9YWV9ES08gPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkgCmBgYAoKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZGF0YV9ES08kbGZjX0RIWDM2IDwtIGRhdGFfREhYMzYkbGZjCmRhdGFfREtPJGxmY19GQU5DSiA8LSBkYXRhX0ZBTkNKJGxmYwpnZ3NjYXR0ZXIoZGF0YV9ES08seCA9ImxmY19ESFgzNiIseT0ibGZjIixjb2xvcj0iZ3JheSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pLCBhZGQgPSAicmVnLmxpbmUiKSsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpLCB4bGltPWMoLTUsNSkpICsgc3RhdF9jb3IoKQpwbG90X0xGQ19ES09fdnNfREhYMzZfcmVnIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfREtPJGxmY19ESFgzNiA8LSBkYXRhX0RIWDM2JGxmYwpkYXRhX0RLTyRsZmNfRkFOQ0ogPC0gZGF0YV9GQU5DSiRsZmMKZ2dzY2F0dGVyKGRhdGFfREtPLHggPSJsZmNfREhYMzYiLHk9ImxmYyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzNdKSwgYWRkID0gInJlZy5saW5lIikrIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSwgeGxpbT1jKC01LDUpKSArIHN0YXRfY29yKCkKcGxvdF9MRkNfREtPX3ZzX0RIWDM2IDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZ2dzY2F0dGVyKGRhdGFfREtPLHggPSJsZmNfRkFOQ0oiLHk9ImxmYyIsY29sb3I9ImdyYXkiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzNdKSwgYWRkPSJyZWcubGluZSIpKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTUsNSksIHhsaW09YygtNSw1KSkgKyBzdGF0X2NvcigpCnBsb3RfTEZDX0RLT192c19GQU5DSl9yZWcgPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpnZ3NjYXR0ZXIoZGF0YV9ES08seCA9ImxmY19GQU5DSiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pKSsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpLCB4bGltPWMoLTUsNSkpICsgc3RhdF9jb3IoKQpwbG90X0xGQ19ES09fdnNfRkFOQ0ogPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkKYGBgCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfREhYMzYkbGZjX0RLTyA8LSBkYXRhX0RLTyRsZmMKZ2dzY2F0dGVyKGRhdGFfREhYMzYseCA9ImxmYyIseT0ibGZjX0RLTyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzFdKSkrIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSwgeGxpbT1jKC01LDUpKQpgYGAKCmBgYHtyfQpiZWQgPC0gYXMuZGF0YS5mcmFtZShjb3YuREhYMzYpWywxOjNdCgpyZXN1bHRzX3RhYmxlIDwtIGRhdGEuZnJhbWUoY2hyPWJlZCRzZXFuYW1lcyxzdGFydD1iZWQkc3RhcnQsZW5kPWJlZCRlbmQsbmFtZT1jb3YuV1QkbmFtZSwgYmFzZU1lYW49bGZjX0RLTyRiYXNlTWVhbixESFgzNj1kYXRhX0RIWDM2JGlzREUsRkFOQ0o9ZGF0YV9GQU5DSiRpc0RFLERLTz1kYXRhX0RLTyRpc0RFLERIWDM2bGZjPWRhdGFfREhYMzYkbGZjLEZBTkNKbGZjPWRhdGFfRkFOQ0okbGZjLERLT2xmYz1kYXRhX0RLTyRsZmMsZGlyPSIuIikKCnJlc3VsdHNfdGFibGUkbm9uc2lnIDwtICEocmVzdWx0c190YWJsZSRESFgzNiB8IHJlc3VsdHNfdGFibGUkRkFOQ0ogfCByZXN1bHRzX3RhYmxlJERLTykKCnJlc3VsdHNfdGFibGUkc2lnIDwtIGZhY3RvcigibG93bGZjIiwgbGV2ZWxzPWMoIm5vbnNpZyIsImxvd2xmYyIsIkZBTkNKIiwiREhYMzYiLCJES08iKSkKcmVzdWx0c190YWJsZSRzaWdbKHJlc3VsdHNfdGFibGUkbm9uc2lnKV0gPC0gIm5vbnNpZyIKcmVzdWx0c190YWJsZSRzaWdbKHJlc3VsdHNfdGFibGUkREtPICYgcmVzdWx0c190YWJsZSRES09sZmM+MSldIDwtICJES08iCnJlc3VsdHNfdGFibGUkc2lnWyhyZXN1bHRzX3RhYmxlJERIWDM2ICYgcmVzdWx0c190YWJsZSRESFgzNmxmYz4xKV0gPC0gIkRIWDM2IgpyZXN1bHRzX3RhYmxlJHNpZ1socmVzdWx0c190YWJsZSRGQU5DSiAmIHJlc3VsdHNfdGFibGUkRkFOQ0psZmM+MSldIDwtICJGQU5DSiIKCndyaXRlLnRhYmxlKHJlc3VsdHNfdGFibGUsIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9yZXN1bHRzLnR4dCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IFQscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQpgYGAKCmBgYHtyfQpyZXN1bHRzX3RhYmxlIDwtIHJlYWQudGFibGUoIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9yZXN1bHRzLnR4dCIsIGhlYWRlciA9IFQsIHNlcCA9ICJcdCIpCnJlc3VsdHNfdGFibGUkc2lnIDwtIGZhY3RvcihyZXN1bHRzX3RhYmxlJHNpZywgbGV2ZWxzPWMoIm5vbnNpZyIsImxvd2xmYyIsIkZBTkNKIiwiREhYMzYiLCJES08iKSkKCkRIWDM2X2JlZCA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJERIWDM2ICYgcmVzdWx0c190YWJsZSRESFgzNmxmYz4xKSxjKDEsMiwzLDQsOSwxMildCndyaXRlLnRhYmxlKERIWDM2X2JlZCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0RIWDM2X3NpZy5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCkZBTkNKX2JlZCA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJEZBTkNKICYgcmVzdWx0c190YWJsZSRGQU5DSmxmYz4xKSxjKDEsMiwzLDQsMTAsMTIpXQp3cml0ZS50YWJsZShGQU5DSl9iZWQsIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9GQU5DSl9zaWcuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpES09fYmVkIDwtIHJlc3VsdHNfdGFibGVbKHJlc3VsdHNfdGFibGUkREtPICYgcmVzdWx0c190YWJsZSRES09sZmM+MSksYygxLDIsMyw0LDExLDEyKV0Kd3JpdGUudGFibGUoREtPX2JlZCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0RLT19zaWcuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpub25zaWdfYmVkIDwtIHJlc3VsdHNfdGFibGVbcmVzdWx0c190YWJsZSRub25zaWcgLGMoMSwyLDMsNCwxMSwxMildCndyaXRlLnRhYmxlKG5vbnNpZ19iZWQsIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9ub25zaWcuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpES09fYmVkX3RvcCA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJERLTz09VFJVRSAmIHJlc3VsdHNfdGFibGUkREtPbGZjPjIgJiByZXN1bHRzX3RhYmxlJGJhc2VNZWFuID4gMTAwKSxjKDEsMiwzLDQsMTEsMTIpXQp3cml0ZS50YWJsZShES09fYmVkX3RvcCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0RLT19zaWdfbGZjX2Jhc2VfY3V0b2ZmLmJlZCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKCndyaXRlLnRhYmxlKGNiaW5kKHJlc3VsdHNfdGFibGVbLGMoMSwyLDMpXSxyZXN1bHRzX3RhYmxlJHNpZyxhcy5udW1lcmljKHJlc3VsdHNfdGFibGUkc2lnKSwiLiIpLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfc2lnX2NhdGVnb3JpZXMuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KbGlicmFyeShldWxlcnIpCnYgPC0gbGlzdChESFgzNj1ESFgzNl9iZWQkbmFtZSxGQU5DSj1GQU5DSl9iZWQkbmFtZSxES089REtPX2JlZCRuYW1lKQpwbG90X1Zlbm5fYWxsIDwtIHBsb3QoZXVsZXIodikscXVhbnRpdGllcz1ULCBib3JkZXI9ImJsYWNrIikKcGxvdF9WZW5uX2FsbApgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KbGlicmFyeShldWxlcnIpCkRLT25lZyA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJERLTz09VFJVRSAmIHJlc3VsdHNfdGFibGUkREtPbGZjPCAtMSksYyg0KV0KdiA8LSBsaXN0KGFsbD1jb3YuV1QkbmFtZSxES09uZWc9REtPbmVnLERLTz1ES09fYmVkJG5hbWUpCnBsb3RfVmVubl9ES08gPC0gcGxvdChldWxlcih2KSxxdWFudGl0aWVzPVQpCnBsb3RfVmVubl9ES08KYGBgCmBgYHtyfQpkaXIuY3JlYXRlKCIuL3Bsb3RzIixzaG93V2FybmluZ3MgPSBGKQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl9NQV9ESFgzNi5wZGYiLHBsb3RfTUFfREhYMzYsd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX01BX0ZBTkNKLnBkZiIscGxvdF9NQV9GQU5DSix3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTUFfREtPLnBkZiIscGxvdF9NQV9ES08sd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX0xGQ19ESFgzNi5wZGYiLHBsb3RfTEZDX0RLT192c19ESFgzNix3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTEZDX0ZBTkNKLnBkZiIscGxvdF9MRkNfREtPX3ZzX0ZBTkNKLHdpZHRoID0gNCwgaGVpZ2h0PSA0KQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl9MRkNfREhYMzZfcmVnLnBkZiIscGxvdF9MRkNfREtPX3ZzX0RIWDM2X3JlZyx3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTEZDX0ZBTkNKX3JlZy5wZGYiLHBsb3RfTEZDX0RLT192c19GQU5DSl9yZWcsd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX1Zlbm5fS09zLnBkZiIscGxvdF9WZW5uX2FsbCx3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfVmVubl9ES09fdnNfYWxsLnBkZiIscGxvdF9WZW5uX0RLTyx3aWR0aCA9IDQsIGhlaWdodD0gNCkKYGBgIAoKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KbGlicmFyeShjb3dwbG90KQpkaXIuY3JlYXRlKCIuL3BhbmVscyIsc2hvd1dhcm5pbmdzID0gRikKCmxpYnJhcnkoImNvd3Bsb3QiKQpwIDwtIGdnZHJhdygpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ESFgzNiwgeCA9IDAsIHkgPSAwLjUsIHdpZHRoID0gLjMzLCBoZWlnaHQgPSAuNSkgKwogIGRyYXdfcGxvdChwbG90X01BX0ZBTkNKLCB4ID0gLjMzLCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gLjUpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ES08sIHggPSAwLjY2LCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfTEZDX0RLT192c19ESFgzNiwgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdChwbG90X0xGQ19ES09fdnNfRkFOQ0osIHggPSAwLjMzLCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF9WZW5uX2FsbCwgeCA9IDAuNjYsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoImEiLCAiYiIsICJjIiwiZCIsImUiLCJmIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMC4zMywgMC42NiwgMCwgMC4zMywgMC42NiksIHkgPSBjKDEsIDEsIDEsIDAuNSwgMC41LCAwLjUpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtzX0RFU2VxMi5wZGYiLHApCmBgYCAKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KbGlicmFyeShjb3dwbG90KQpkaXIuY3JlYXRlKCIuL3BhbmVscyIsc2hvd1dhcm5pbmdzID0gRikKCmxpYnJhcnkoImNvd3Bsb3QiKQpwIDwtIGdnZHJhdygpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ESFgzNiwgeCA9IDAsIHkgPSAwLjUsIHdpZHRoID0gLjMzLCBoZWlnaHQgPSAuNSkgKwogIGRyYXdfcGxvdChwbG90X01BX0ZBTkNKLCB4ID0gLjMzLCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gLjUpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ES08sIHggPSAwLjY2LCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfWFlfREhYMzYsIHggPSAwLCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF9YWV9GQU5DSiwgeCA9IDAuMzMsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdChwbG90X1hZX0RLTywgeCA9IDAuNjYsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoImEiLCAiYiIsICJjIiwiZCIsImUiLCJmIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMC4zMywgMC42NiwgMCwgMC4zMywgMC42NiksIHkgPSBjKDEsIDEsIDEsIDAuNSwgMC41LCAwLjUpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtzX0RFU2VxMl9zY2F0dGVyLnBkZiIscCkKYGBgIAoKYGBge3J9CmNvdiA8LSBjYmluZCggYXMuZGF0YS5mcmFtZShjb3YuV1QpWywxOjhdLCAKICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGNvdi5ESFgzNilbLDY6OF0sIAogICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoY292LkZBTkNKKVssNjo4XSwgCiAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShjb3YuREtPKVssNjo4XSkKCmNvbG5hbWVzKGNvdikgPC0gYyhjb2xuYW1lcyhjb3YpWzE6NV0sIldUMSIsIldUMiIsIldUMyIsIkRIWDEiLCJESFgyIiwiREhYMyIsIkZBTjEiLCJGQU4yIiwiRkFOMyIsIkRLTzEiLCJES08yIiwiREtPMyIpCgpyb3duYW1lcyhjb3YpIDwtIGFzLmRhdGEuZnJhbWUoY292LldUKSRuYW1lCgpjb3YkREhYMzZfc2lnIDwtIHJvd25hbWVzKGNvdikgJWluJSBESFgzNl9iZWQkbmFtZQpjb3YkRkFOQ0pfc2lnIDwtIHJvd25hbWVzKGNvdikgJWluJSBGQU5DSl9iZWQkbmFtZQpjb3YkREtPX3NpZyA8LSByb3duYW1lcyhjb3YpICVpbiUgREtPX2JlZCRuYW1lCmNvdiRub25fc2lnIDwtIHdpdGgoY292LCAhKERIWDM2X3NpZyB8IEZBTkNKX3NpZyB8IERLT19zaWcpKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CmxpYnJhcnkocmVzaGFwZTIpCm1kZiA8LSBtZWx0KGRhdGEuZnJhbWUobmFtZT1yb3duYW1lcyhjb3YpLGNvdlssNjoyMV0pKQptZGYgPC0gbWRmW21kZiR2YWx1ZTw1MDAsXQptZGYkY29uZCA8LSAiV1QiCm1kZiRjb25kW2dyZXAoIkRIWCIsbWRmJHZhcmlhYmxlKV0gPC0gIkRIWDM2LS8tIgptZGYkY29uZFtncmVwKCJGQU4iLG1kZiR2YXJpYWJsZSldIDwtICJGQU5DSi0vLSIKbWRmJGNvbmRbZ3JlcCgiREtPIixtZGYkdmFyaWFibGUpXSA8LSAiREhYMzYtLy1GQU5DSi0vLSIKcGxvdF92aW9sX3JlcF9hbGxfcGVha3MgPC0gZ2d2aW9saW4obWRmLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfYWxsX3BlYWtzCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF92aW9sX3JlcF9ESFgzNl9wZWFrcyA8LSBnZ3Zpb2xpbihtZGZbbWRmJERIWDM2X3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfREhYMzZfcGVha3MKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpnZ3Zpb2xpbihtZGZbbWRmJEZBTkNKX3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF92aW9sX3JlcF9ES09fcGVha3MgPC0gZ2d2aW9saW4obWRmW21kZiRES09fc2lnLF0sIHg9InZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUwKSkKcGxvdF92aW9sX3JlcF9ES09fcGVha3MKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnBsb3RfdmlvbF9yZXBfbm9uc2lnX3BlYWtzIDwtIGdndmlvbGluKG1kZlttZGYkbm9uX3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfbm9uc2lnX3BlYWtzCmBgYAoKYGBge3J9Cmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX3Zpb2xfcmVwX2FsbC5wZGYiLHBsb3RfdmlvbF9yZXBfYWxsX3BlYWtzKQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl92aW9sX3JlcF9ES08ucGRmIixwbG90X3Zpb2xfcmVwX0RLT19wZWFrcykKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfdmlvbF9yZXBfREhYMzYucGRmIixwbG90X3Zpb2xfcmVwX0RIWDM2X3BlYWtzKQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl92aW9sX3JlcF9ub25zaWcucGRmIixwbG90X3Zpb2xfcmVwX25vbnNpZ19wZWFrcykKYGBgIAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30Kc2RmIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IG5hbWUgKyBjb25kLCBkYXRhPW1kZiwgRlVOPSJtZWFuIikKc2RmJGNvbmQgPC0gZmFjdG9yKHNkZiRjb25kLGxldmVscz1jKCJXVCIsIkRIWDM2LS8tIiwiRkFOQ0otLy0iLCJESFgzNi0vLUZBTkNKLS8tIikpCmdndmlvbGluKHNkZiwgeD0iY29uZCIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbFtjKDQsMSwyLDMpXSwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30Kc2RmJERIWDM2X3NpZyA8LSBzZGYkbmFtZSAlaW4lIERIWDM2X2JlZCRuYW1lCnNkZiRGQU5DSl9zaWcgPC0gc2RmJG5hbWUgJWluJSBGQU5DSl9iZWQkbmFtZQpzZGYkREtPX3NpZyA8LSBzZGYkbmFtZSAlaW4lIERLT19iZWQkbmFtZQpzZGYkREtPX3RvcCA8LSBzZGYkbmFtZSAlaW4lIERLT19iZWRfdG9wJG5hbWUKZ2d2aW9saW4oc2RmW3NkZiRESFgzNixdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpnZ3Zpb2xpbihzZGZbc2RmJEZBTkNKX3NpZyxdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X3Zpb2xfREtPX3BlYWtzIDwtIGdndmlvbGluKHNkZltzZGYkREtPX3NpZyxdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKcGxvdF92aW9sX0RLT19wZWFrcwpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CmdndmlvbGluKHNkZltzZGYkREtPX3RvcCxdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKYGBgCgojIyMgYW5ub3RhdGUgcGVhayB0YWJsZQpgYGB7cn0KbGlicmFyeShiZWRzY291dCkKCnBlYWtfdW5pdmVyc2UgPC0gIi4uL3BlYWtzL0c0X2NvbWJpbmVkX21pbjNyZXAuYmVkIgoKYmVkX3BlYWtzIDwtIHJ0cmFja2xheWVyOjppbXBvcnQocGVha191bml2ZXJzZSkKY2hyb21obW1fZ3IgPC0gcnRyYWNrbGF5ZXI6OmltcG9ydChjaHJvbWhtbSkKCgpiZWRfcGVha3NfYW5ub3RhdGVkIDwtIHVuaXF1ZShpbXB1dGVfZmVhdHVyZShiZWRfcGVha3MsIGNocm9taG1tX2dyLCAibmFtZSIpKQpiZWRfcGVha3NfYW5ub3RhdGVkX2RmIDwtIGFzLmRhdGEuZnJhbWUoYmVkX3BlYWtzX2Fubm90YXRlZCkKIyBJZiB5b3Ugd2FudCB0byBleHBvcnQgdG8gQkVEIGZpbGUgd2l0aCBydHJhY2tsYXllciB0aGVuIHlvdQojIGRvIG5lZWQgdG8gZXhwbGljaXRseSBvdmVyd3JpdGUgdGhlIG5hbWU6CmJlZF9wZWFrc19hbm5vdGF0ZWQkbmFtZSA8LSBiZWRfcGVha3NfYW5ub3RhdGVkJGZlYXR1cmUKcnRyYWNrbGF5ZXI6OmV4cG9ydCh1bmlxdWUoYmVkX3BlYWtzX2Fubm90YXRlZCksICIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfYW5ub3RhdGVkX3YyLmJlZCIpCgpjaHJvbWhtbTE3X2dyIDwtIHJ0cmFja2xheWVyOjppbXBvcnQoIi4uL2dlbm9tZS9DaHJvbUhNTTE3LmNocjkubW0zOWxpZnQuYmVkIikKYmVkX3BlYWtzX2htbTE3IDwtIHVuaXF1ZShpbXB1dGVfZmVhdHVyZShiZWRfcGVha3MsIGNocm9taG1tMTdfZ3IsICJuYW1lIikpCiMgSWYgeW91IHdhbnQgdG8gZXhwb3J0IHRvIEJFRCBmaWxlIHdpdGggcnRyYWNrbGF5ZXIgdGhlbiB5b3UKIyBkbyBuZWVkIHRvIGV4cGxpY2l0bHkgb3ZlcndyaXRlIHRoZSBuYW1lOgpiZWRfcGVha3NfaG1tMTckbmFtZSA8LSBiZWRfcGVha3NfaG1tMTckZmVhdHVyZQpiZWRfcGVha3NfaG1tMTckc2NvcmVbaXMubmEoYmVkX3BlYWtzX2htbTE3JHNjb3JlKV0gPC0gMApydHJhY2tsYXllcjo6ZXhwb3J0KGJlZF9wZWFrc19obW0xNywgIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9hbm5vdGF0ZWRfQ2hyb21ITU0xNy5iZWQiKQoKcm1za19nciA8LSBydHJhY2tsYXllcjo6aW1wb3J0KCIuLi9nZW5vbWUvcm1zay5sdDIwMGJwLm1tMzkuYmVkIikKYmVkX3BlYWtzX3Jtc2sgPC0gaW1wdXRlX2ZlYXR1cmUoYmVkX3BlYWtzLCBybXNrX2dyLCAibmFtZSIpCiMgSWYgeW91IHdhbnQgdG8gZXhwb3J0IHRvIEJFRCBmaWxlIHdpdGggcnRyYWNrbGF5ZXIgdGhlbiB5b3UKIyBkbyBuZWVkIHRvIGV4cGxpY2l0bHkgb3ZlcndyaXRlIHRoZSBuYW1lOgpiZWRfcGVha3Nfcm1zayRuYW1lIDwtIGJlZF9wZWFrc19ybXNrJGZlYXR1cmUKYmVkX3BlYWtzX3Jtc2skc2NvcmVbaXMubmEoYmVkX3BlYWtzX3Jtc2skc2NvcmUpXSA8LSAwCnJ0cmFja2xheWVyOjpleHBvcnQoYmVkX3BlYWtzX3Jtc2ssICIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfYW5ub3RhdGVkX3Jtc2suYmVkIikKCmJlZF9wZWFrc190YWJsZSA8LSBjYmluZChiZWRfcGVha3NfYW5ub3RhdGVkX2RmLGRhdGEuZnJhbWUoYmFzZU1lYW49bGZjX0RLTyRiYXNlTWVhbixub25zaWc9KCFkYXRhX0RIWDM2JGlzREUgJiAhZGF0YV9GQU5DSiRpc0RFICYgIWRhdGFfREtPJGlzREUpLCBESFgzNj0oZGF0YV9ESFgzNiRpc0RFICYgZGF0YV9ESFgzNiRsZmM+MSksRkFOQ0o9KGRhdGFfRkFOQ0okaXNERSAmIGRhdGFfRkFOQ0okbGZjPjEpLERLTz0oZGF0YV9ES08kaXNERSZkYXRhX0RLTyRsZmM+MSksREhYMzZsZmM9ZGF0YV9ESFgzNiRsZmMsRkFOQ0psZmM9ZGF0YV9GQU5DSiRsZmMsREtPbGZjPWRhdGFfREtPJGxmYykpCgp3cml0ZS50YWJsZShiZWRfcGVha3NfdGFibGUsIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9hbm5vdGF0ZWRfdjIudHh0Iiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gVCxxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9Mn0KI3JlYWQgaW4gLSBpZiB5b3Ugd2FudCB0byBza2lwIGRlIG5vdm8gZ2VuZXJhdGlvbgpiZWRfcGVha3NfdGFibGUgPC0gcmVhZC50YWJsZSgiRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX2Fubm90YXRlZF92Mi50eHQiLCBoZWFkZXIgPSBULCBzZXAgPSAiXHQiKQoKdnBhbD1jb2xvclJhbXBQYWxldHRlKGMoImNvcm5mbG93ZXJibHVlIiwib3JhbmdlIiwicmVkMiIpKQpzdGF0cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlKSkKcGxvdF9kb251dF9hbGwgPC0gZ2dkb251dGNoYXJ0KHN0YXRzLHggPSAiRnJlcSIsbGFiZWw9IlZhcjEiLGZpbGw9dnBhbCgxMCkpCnBsb3RfZG9udXRfYWxsCmBgYAoKIyMjIERKIFBlYWsgQW5ub3RhdGlvbgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0yfQpiZWRfREogPC0gYmVkX3BlYWtzX3RhYmxlW2JlZF9wZWFrc190YWJsZSRES08sYygxLDIsMyw2LDE2LDUpXQpiZWRfREokbmFtZSA8LSAiREoiCndyaXRlLnRhYmxlKGJlZF9ESiwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RKLmJlZCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKc3RhdHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZVtiZWRfcGVha3NfdGFibGUkREtPXSkpCnBsb3RfZG9udXRfREogPC0gZ2dkb251dGNoYXJ0KHN0YXRzLHggPSAiRnJlcSIsbGFiZWw9IlZhcjEiLGZpbGw9dnBhbCgxMCkpCnBsb3RfZG9udXRfREoKYGBgCgojIyMgbm9uLURKIFBlYWsgQW5ub3RhdGlvbgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0yfQpiZWRfbm9uREogPC0gYmVkX3BlYWtzX3RhYmxlW2JlZF9wZWFrc190YWJsZSRub25zaWcsYygxLDIsMyw2LDE2LDUpXQpiZWRfbm9uREokbmFtZSA8LSAibm9uREoiCndyaXRlLnRhYmxlKGJlZF9ub25ESiwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX25vbkRKLmJlZCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKYmVkX0RKJERLT2xmYyA8LSAxCmJlZF9ub25ESiRES09sZmMgPC0gMAoKd3JpdGUudGFibGUocmJpbmQoYmVkX0RKLGJlZF9ub25ESiksIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ESl9ub25ESi5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCnN0YXRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJG5vbnNpZ10pKQpwbG90X2RvbnV0X25vbkRKIDwtIGdnZG9udXRjaGFydChzdGF0cyx4ID0gIkZyZXEiLGxhYmVsPSJWYXIxIixmaWxsPXZwYWwoMTApKQpwbG90X2RvbnV0X25vbkRKCmBgYApgYGB7cn0KZ2dzYXZlKCJwbG90cy9wbG90X2RvbnV0X0RKLnBkZiIscGxvdF9kb251dF9ESikKZ2dzYXZlKCJwbG90cy9wbG90X2RvbnV0X25vbkRKLnBkZiIscGxvdF9kb251dF9ub25ESikKZ2dzYXZlKCJwbG90cy9wbG90X2RvbnV0X2FsbC5wZGYiLHBsb3RfZG9udXRfYWxsKQpgYGAgCgoKYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NH0KdnBhbD1jb2xvclJhbXBQYWxldHRlKGMoImxpZ2h0Z3JlZW4iLCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiKSkKCnN0YXRzIDwtIGRhdGEuZnJhbWUoYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZSkpWzFdLGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJERLT10pKVsyXSxhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlW2JlZF9wZWFrc190YWJsZSRub25zaWddKSlbMl0pCgpjb2xuYW1lcyhzdGF0cykgPC0gYygiU3RhdGUiLCJESiIsIm5vbkRKIikKCiNzdGF0cyRESFgzNj1zdGF0cyRESi9zdW0oc3RhdHMkREopKjEwMAojc3RhdHMkRkFOQ0o9c3RhdHMkbm9uREovc3VtKHN0YXRzJG5vbkRKKSoxMDAKCm1kZiA8LSBtZWx0KHN0YXRzKQptZGYkU3RhdGUgPC0gZmFjdG9yKG1kZiRTdGF0ZSxsZXZlbHM9bGV2ZWxzKG1kZiRTdGF0ZSlbYygxLDMsNSw3LDQsNiwxMCw4LDksMildKQpjb2xzPWModnBhbCgxMSlbYyg0LDUsMywyLDksOCw3KV0sIiNEREREREQiLCIjRUVFRUVFIix2cGFsKDExKVsxMF0pCnBsb3RfYmFyX2Nocm9taG1tX2Fubm8gPC0gZ2diYXJwbG90KG1kZix4ID0gInZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iU3RhdGUiLHBhbGV0dGUgPWNvbHMsICBvcmllbnRhdGlvbiA9IGMoImhvcml6b250YWwiKSkgCnBsb3RfYmFyX2Nocm9taG1tX2Fubm8KYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD00fQp2cGFsPWNvbG9yUmFtcFBhbGV0dGUoYygibGlnaHRncmVlbiIsImNvcm5mbG93ZXJibHVlIiwib3JhbmdlIiwicmVkMiIpKQoKc3RhdHMgPC0gZGF0YS5mcmFtZShhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlKSlbMV0sYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZSkpWzJdLGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJERLT10pKVsyXSxhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlW2JlZF9wZWFrc190YWJsZSRub25zaWddKSlbMl0pCgpjb2xuYW1lcyhzdGF0cykgPC0gYygiU3RhdGUiLCJhbGwiLCJESiIsIm5vbkRKIikKCiNzdGF0cyRESFgzNj1zdGF0cyRESi9zdW0oc3RhdHMkREopKjEwMAojc3RhdHMkRkFOQ0o9c3RhdHMkbm9uREovc3VtKHN0YXRzJG5vbkRKKSoxMDAKCm1kZiA8LSBtZWx0KHN0YXRzKQptZGYkU3RhdGUgPC0gZmFjdG9yKG1kZiRTdGF0ZSxsZXZlbHM9bGV2ZWxzKG1kZiRTdGF0ZSlbYygxLDMsNSw3LDQsNiwxMCw4LDksMildKQpjb2xzPWModnBhbCgxMSlbYyg0LDUsMywyLDksOCw3KV0sIiNEREREREQiLCIjRUVFRUVFIix2cGFsKDExKVsxMF0pCnBsb3RfYmFyX2Nocm9taG1tX2Fubm9fYWxsIDwtIGdnYmFycGxvdChtZGYseCA9ICJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9IlN0YXRlIixwYWxldHRlID1jb2xzLCAgb3JpZW50YXRpb24gPSBjKCJob3Jpem9udGFsIikpIApwbG90X2Jhcl9jaHJvbWhtbV9hbm5vX2FsbApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTR9CnN0YXRzJERKPXN0YXRzJERKL3N1bShzdGF0cyRESikqMTAwCnN0YXRzJG5vbkRKPXN0YXRzJG5vbkRKL3N1bShzdGF0cyRub25ESikqMTAwCnN0YXRzJGFsbD1zdGF0cyRhbGwvc3VtKHN0YXRzJGFsbCkqMTAwCm1kZiA8LSBtZWx0KHN0YXRzKQptZGYkU3RhdGUgPC0gZmFjdG9yKG1kZiRTdGF0ZSxsZXZlbHM9bGV2ZWxzKG1kZiRTdGF0ZSlbYygxLDMsNSw3LDQsNiwxMCw4LDksMildKQpjb2xzPWModnBhbCgxMSlbYyg0LDUsMywyLDksOCw3KV0sIiNEREREREQiLCIjRUVFRUVFIix2cGFsKDExKVsxMF0pCnBsb3RfYmFyX2Nocm9taG1tX2Fubm9fbm9ybSA8LSBnZ2JhcnBsb3QobWRmLHggPSAidmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJTdGF0ZSIscGFsZXR0ZSA9Y29scywgIG9yaWVudGF0aW9uID0gYygiaG9yaXpvbnRhbCIpKSAKcGxvdF9iYXJfY2hyb21obW1fYW5ub19ub3JtCmBgYApgYGB7cn0KZ2dzYXZlKCJwbG90cy9wbG90X2Jhcl9jaHJvbWhtbS5wZGYiLHBsb3RfYmFyX2Nocm9taG1tX2Fubm8pCmdnc2F2ZSgicGxvdHMvcGxvdF9iYXJfY2hyb21obW1fcmVsLnBkZiIscGxvdF9iYXJfY2hyb21obW1fYW5ub19ub3JtKQpgYGAgCgpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0zfQp2cGFsPWNvbG9yUmFtcFBhbGV0dGUoYygibGlnaHRncmVlbiIsImNvcm5mbG93ZXJibHVlIiwib3JhbmdlIiwicmVkMiIpKQoKc3RhdHMgPC0gZGF0YS5mcmFtZShhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlKSksREhYMzY9YXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZVtiZWRfcGVha3NfdGFibGUkREhYMzY9PVRSVUVdKSlbMl0sRkFOQ0o9YXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZVtiZWRfcGVha3NfdGFibGUkRkFOQ0o9PVRSVUVdKSlbMl0sREtPPWFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJERLTz09VFJVRV0pKVsyXSkKY29sbmFtZXMoc3RhdHMpIDwtIGMoIlN0YXRlIiwiVG90YWwiLCJESFgzNiIsIkZBTkNKIiwiREtPIikKCnN0YXRzJFRvdGFsPXN0YXRzJFRvdGFsL3N1bShzdGF0cyRUb3RhbCkqMTAwCnN0YXRzJERIWDM2PXN0YXRzJERIWDM2L3N1bShzdGF0cyRESFgzNikqMTAwCnN0YXRzJEZBTkNKPXN0YXRzJEZBTkNKL3N1bShzdGF0cyRGQU5DSikqMTAwCnN0YXRzJERLTz1zdGF0cyRES08vc3VtKHN0YXRzJERLTykqMTAwCm1kZiA8LSBtZWx0KHN0YXRzKQptZGYkU3RhdGUgPC0gZmFjdG9yKG1kZiRTdGF0ZSxsZXZlbHM9bGV2ZWxzKG1kZiRTdGF0ZSlbYygxLDMsNSw3LDQsNiwxMCw4LDksMildKQpjb2xzPWModnBhbCgxMSlbYyg0LDUsMywyLDksOCw3KV0sIiNEREREREQiLCIjRUVFRUVFIix2cGFsKDExKVsxMF0pCnBsb3RfYmFyX2Nocm9taG1tX2Fubm8gPC0gZ2diYXJwbG90KG1kZix4ID0gInZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iU3RhdGUiLHBhbGV0dGUgPWNvbHMsbGFiZWw9bWRmJFN0YXRlKQpwbG90X2Jhcl9jaHJvbWhtbV9hbm5vCmBgYAoKCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zfQpwIDwtIGdnZHJhdygpICsKICBkcmF3X3Bsb3QocGxvdF9iYXJfY2hyb21obW1fYW5ubywgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IC4yMCwgaGVpZ2h0ID0gMSkgKwogIGRyYXdfcGxvdChwbG90X3Zpb2xfcmVwX0RLT19wZWFrcywgeCA9IC4yLCB5ID0gMCwgd2lkdGggPSAuNDAsIGhlaWdodCA9IDAuNykgKwogIGRyYXdfcGxvdChwbG90X3Zpb2xfcmVwX25vbnNpZ19wZWFrcywgeCA9IDAuNiwgeSA9IDAsIHdpZHRoID0gLjQwLCBoZWlnaHQgPSAwLjcpICsKICBkcmF3X3Bsb3RfbGFiZWwobGFiZWwgPSBjKCJhIiwgImIiLCAiYyIpLCBzaXplID0gMTUsCiAgICAgICAgICAgICAgICAgIHggPSBjKDAsIDAuMiwgMC42KSwgeSA9IGMoMSwgMC44LCAwLjgpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtfYW5ub192aW9saW5fdjEucGRmIixwKQpgYGAgCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTN9CgpwIDwtIGdnZHJhdygpICsKICBkcmF3X3Bsb3QocGxvdF9iYXJfY2hyb21obW1fYW5ubywgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IC40LCBoZWlnaHQgPSAxKSArCiAgZHJhd19wbG90KHBsb3RfdmlvbF9yZXBfREtPX3BlYWtzLCB4ID0gLjQsIHkgPSAwLjUsIHdpZHRoID0gLjYwLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF92aW9sX3JlcF9ub25zaWdfcGVha3MsIHggPSAwLjQsIHkgPSAwLCB3aWR0aCA9IC42MCwgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiYSIsICJiIiwgImMiKSwgc2l6ZSA9IDE1LAogICAgICAgICAgICAgICAgICB4ID0gYygwLCAwLjQsIDAuNCksIHkgPSBjKDEsIDEsIDAuNSkpCnAKZ2dzYXZlKCJwYW5lbHMvcGVha19hbm5vX3Zpb2xpbl92Mi5wZGYiLHApCmBgYCAK